home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / BeOS / SheepDriver / sheep_driver.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-31  |  11.5 KB  |  477 lines

  1. /*
  2.  *  sheep_driver.c - Low memory and ROM access driver for SheepShaver and
  3.  *                   Basilisk II on PowerPC systems
  4.  *
  5.  *  SheepShaver (C) 1997-2001 Mar"c Hellwig and Christian Bauer
  6.  *  Basilisk II (C) 1997-2001 Christian Bauer
  7.  *
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21.  */
  22.  
  23. #ifdef __i386__
  24. #error The sheep driver only runs on PowerPC machines.
  25. #endif
  26.  
  27. #include <drivers/KernelExport.h>
  28. #include <drivers/Drivers.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <stdarg.h>
  32. #include <string.h>
  33. #include <fcntl.h>
  34.  
  35. #include "sheep_driver.h"
  36.  
  37. #define DEBUG 0
  38.  
  39. #if DEBUG==1
  40. #define bug pprintf
  41. #elif DEBUG==2
  42. #define bug dprintf
  43. #endif
  44.  
  45. #if DEBUG
  46. #define D(x) (x)
  47. #else
  48. #define D(x) ;
  49. #endif
  50.  
  51. #define PORT_NAME "sheep_driver installed"
  52.  
  53.  
  54. /*
  55.  *  For debugging
  56.  */
  57.  
  58. static int pprintf(const char* format, ...)
  59. {
  60.     port_id PortNum;
  61.     int len, ret;
  62.     char Buffer[1024];
  63.     va_list ap;
  64.     
  65.     if ((PortNum = find_port("PortLogger")) == B_NAME_NOT_FOUND)
  66.         return(PortNum);
  67.     for (len=0; len<1024; len++)
  68.         Buffer[len]='\0'; 
  69.     va_start(ap, format);
  70.     vsprintf(Buffer, format, ap);
  71.     ret = write_port(PortNum, 0, Buffer, strlen(Buffer));
  72.     return ret;
  73. }
  74.  
  75.  
  76. /*
  77.  *  Page table functions
  78.  */
  79.  
  80. static uint32 *pte_address = 0;
  81. static uint32 vsid;
  82. static uint32 table_size;
  83.  
  84. static status_t map_page(uint32 ea, uint32 ra, uint32 **free_pte, uint32 bits)
  85. {
  86.     int i;
  87.     int pte_class;
  88.     uint32 hash1, hash2, api, *pteg1, *pteg2;
  89.  
  90.     D(bug("Trying to map EA %p -> RA %p\n", ea, ra));
  91.  
  92.     // Find PTEG addresses for given EA 
  93.     hash1 = (vsid & 0x7ffff) ^ ((ea >> 12) & 0xffff);
  94.     hash2 = ~hash1 & 0x7ffff;
  95.     api = (ea >> 22) & 0x3f;
  96.     pteg1 = (uint32 *)((uint32)pte_address + ((hash1 << 6) & (table_size - 1)));
  97.     pteg2 = (uint32 *)((uint32)pte_address + ((hash2 << 6) & (table_size - 1)));
  98.     D(bug("PTEG1 at %p, PTEG2 at %p\n", pteg1, pteg2));
  99.  
  100.     // Search all 8 PTEs of each PTEG
  101.     *free_pte = NULL;
  102.     pte_class = 0;
  103.     for (i=0; i<8; i++) {
  104.         D(bug(" found %08lx %08lx\n", pteg1[i*2], pteg1[i*2+1]));
  105.         if (pteg1[i*2] == (0x80000000 | (vsid << 7) | (pte_class << 6) | api)) {
  106.             *free_pte = pteg1 + i*2;
  107.             D(bug(" existing PTE found (PTEG1)\n"));
  108.             break;
  109.         } else if (!pteg1[i*2]) {
  110.             *free_pte = pteg1 + i*2;
  111.             D(bug(" free PTE found (PTEG1)\n"));
  112.             break;
  113.         }
  114.     }
  115.     if (*free_pte == NULL) {
  116.         pte_class = 1;
  117.         for (i=0; i<8; i++) {
  118.             D(bug(" found %08lx %08lx\n", pteg2[i*2], pteg2[i*2+1]));
  119.             if (pteg2[i*2] == (0x80000000 | (vsid << 7) | (pte_class << 6) | api)) {
  120.                 *free_pte = pteg2 + i*2;
  121.                 D(bug(" existing PTE found (PTEG2)\n"));
  122.                 break;
  123.             } else if (!pteg2[i*2]) {
  124.                 *free_pte = pteg2 + i*2;
  125.                 D(bug(" free PTE found (PTEG2)\n"));
  126.                 break;
  127.             }
  128.         }
  129.     }
  130.  
  131.     // Remap page
  132.     if (*free_pte == NULL) {
  133.         D(bug(" No free PTE found :-(\m"));
  134.         return B_DEVICE_FULL;
  135.     } else {
  136.         (*free_pte)[0] = 0x80000000 | (vsid << 7) | (pte_class << 6) | api;
  137.         (*free_pte)[1] = ra | bits;
  138.         D(bug(" written %08lx %08lx to PTE\n", (*free_pte)[0], (*free_pte)[1]));
  139.         return B_NO_ERROR;
  140.     }
  141. }
  142.  
  143. static status_t remap_page(uint32 *free_pte, uint32 ra, uint32 bits)
  144. {
  145.     D(bug("Remapping PTE %p -> RA %p\n", free_pte, ra));
  146.  
  147.     // Remap page
  148.     if (free_pte == NULL) {
  149.         D(bug(" Invalid PTE :-(\n"));
  150.         return B_BAD_ADDRESS;
  151.     } else {
  152.         free_pte[1] = ra | bits;
  153.         D(bug(" written %08lx %08lx to PTE\n", free_pte[0], free_pte[1]));
  154.         return B_NO_ERROR;
  155.     }
  156. }
  157.  
  158.  
  159. /*
  160.  *  Foward declarations for hook functions
  161.  */
  162.  
  163. static status_t sheep_open(const char *name, uint32 flags, void **cookie);
  164. static status_t sheep_close(void *cookie);
  165. static status_t sheep_free(void *cookie);
  166. static status_t sheep_control(void *cookie, uint32 op, void *data, size_t len);
  167. static status_t sheep_read(void *cookie, off_t pos, void *data, size_t *len);
  168. static status_t sheep_write(void *cookie, off_t pos, const void *data, size_t *len);
  169.  
  170.  
  171. /*
  172.  *  Version of our driver
  173.  */
  174.  
  175. int32 api_version = B_CUR_DRIVER_API_VERSION;
  176.  
  177.  
  178. /*
  179.  *  Device_hooks structure - has function pointers to the
  180.  *  various entry points for device operations
  181.  */
  182.  
  183. static device_hooks my_device_hooks = {
  184.     &sheep_open,
  185.     &sheep_close,
  186.     &sheep_free,
  187.     &sheep_control,
  188.     &sheep_read,
  189.     &sheep_write,
  190.     NULL,
  191.     NULL,
  192.     NULL,
  193.     NULL
  194. };
  195.  
  196.  
  197. /*
  198.  *  List of device names to be returned by publish_devices()
  199.  */
  200.  
  201. static char *device_name_list[] = {
  202.     "sheep",
  203.     0
  204. };
  205.  
  206.  
  207. /*
  208.  *  Init - do nothing
  209.  */
  210.  
  211. status_t init_hardware(void)
  212. {
  213. #if DEBUG==2
  214.     set_dprintf_enabled(true);
  215. #endif
  216.     D(bug("init_hardware()\n"));
  217.     return B_NO_ERROR;
  218. }
  219.  
  220. status_t init_driver(void)
  221. {
  222.     D(bug("init_driver()\n"));
  223.     return B_NO_ERROR;
  224. }
  225.  
  226. void uninit_driver(void)
  227. {
  228.     D(bug("uninit_driver()\n"));
  229. }
  230.  
  231.  
  232. /*
  233.  *  publish_devices - return list of device names implemented by this driver
  234.  */
  235.  
  236. const char **publish_devices(void)
  237. {
  238.     return device_name_list;
  239. }
  240.  
  241.  
  242. /*
  243.  *  find_device - return device hooks for a specific device name
  244.  */
  245.  
  246. device_hooks *find_device(const char *name)
  247. {
  248.     if (!strcmp(name, device_name_list[0]))
  249.         return &my_device_hooks;
  250.     
  251.     return NULL;
  252. }
  253.  
  254.  
  255. /*
  256.  *  sheep_open - hook function for the open call.
  257.  */
  258.  
  259. static status_t sheep_open(const char *name, uint32 flags, void **cookie)
  260. {
  261.     return B_NO_ERROR;
  262. }
  263.  
  264.  
  265. /*
  266.  *  sheep_close - hook function for the close call.
  267.  */
  268.  
  269. static status_t sheep_close(void *cookie)
  270. {
  271.     return B_NO_ERROR;
  272. }
  273.  
  274.  
  275. /*
  276.  *  sheep_free - hook function to free the cookie returned
  277.  *  by the open hook.  Since the open hook did not return
  278.  *  a cookie, this is a no-op.
  279.  */
  280.  
  281. static status_t sheep_free(void *cookie)
  282. {
  283.     return B_NO_ERROR;
  284. }
  285.  
  286.  
  287. /*
  288.  *  sheep_control - hook function for the ioctl call
  289.  */
  290.  
  291. static asm void inval_tlb(uint32 ea)
  292. {
  293.     isync
  294.     tlbie    r3
  295.     sync
  296.     blr
  297. }
  298.  
  299. static asm void tlbsync(void)
  300. {
  301.     machine 604
  302.     tlbsync
  303.     sync
  304.     blr
  305. }
  306.  
  307. static status_t sheep_control(void *cookie, uint32 op, void *data, size_t len)
  308. {
  309.     static void *block;
  310.     static void *block_aligned;
  311.     physical_entry pe[2];
  312.     system_info sysinfo;
  313.     area_id id;
  314.     area_info info;
  315.     cpu_status cpu_st;
  316.     status_t res;
  317.     uint32 ra0, ra1;
  318.     uint32 *free_pte_0, *free_pte_1;
  319.     int i;
  320.  
  321.     D(bug("control(%d) data %p, len %08x\n", op, data, len));
  322.  
  323.     switch (op) {
  324.         case SHEEP_UP:
  325.     
  326.             // Already messed up? Then do nothing now
  327.             if (find_port(PORT_NAME) != B_NAME_NOT_FOUND)
  328.                 return B_NO_ERROR;
  329.  
  330.             // Get system info
  331.             get_system_info(&sysinfo);
  332.  
  333.             // Prepare replacement memory
  334.             block = malloc(B_PAGE_SIZE * 3);
  335.             D(bug("3 pages malloc()ed at %p\n", block));
  336.             block_aligned = (void *)(((uint32)block + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE-1));
  337.             D(bug("Address aligned to %p\n", block_aligned));
  338.             res = lock_memory(block_aligned, B_PAGE_SIZE * 2, 0);
  339.             if (res < 0)
  340.                 return res;
  341.  
  342.             // Get memory mapping
  343.             D(bug("Memory locked\n"));
  344.             res = get_memory_map(block_aligned, B_PAGE_SIZE * 2, pe, 2);
  345.             D(bug("get_memory_map returned %d\n", res));
  346.             if (res != B_NO_ERROR)
  347.                 return res;
  348.  
  349.             // Find PTE table area
  350.             id = find_area("pte_table");
  351.             get_area_info(id, &info);
  352.             pte_address = (uint32 *)info.address;
  353.             D(bug("PTE table seems to be at %p\n", pte_address));
  354.             table_size = info.size;
  355.             D(bug("PTE table size: %dKB\n", table_size / 1024));
  356.  
  357.             // Disable interrupts
  358.             cpu_st = disable_interrupts();
  359.  
  360.             // Find vsid and real addresses of replacement memory
  361.             for (i=0; i<table_size/8; i++) {
  362.                 if (((uint32)pe[0].address & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) { 
  363.                     D(bug("Found page 0  PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n", 
  364.                       i << 2,
  365.                       ((pte_address[i*2]&0x80000000) >> 31),((pte_address[i*2]&0x7fffff80) >> 7),
  366.                       ((pte_address[i*2]&0x00000040) >> 6),(pte_address[i*2] & 0x3f),
  367.                       ((pte_address[i*2+1]&0xfffff000) >> 12),((pte_address[i*2+1]&0x00000100) >> 8),
  368.                       ((pte_address[i*2+1]&0x00000080) >> 7),((pte_address[i*2+1]&0x00000078) >> 3),
  369.                       (pte_address[i*2+1]&0x00000003)));
  370.                     vsid = (pte_address[i*2]&0x7fffff80) >> 7;
  371.                     ra0 = (uint32)pe[0].address & 0xfffff000;
  372.                 }
  373.                 if ((uint32)pe[0].size == B_PAGE_SIZE) {
  374.                     if (((uint32)pe[1].address & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) {
  375.                         D(bug("Found page 1f PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n", 
  376.                           i << 2,
  377.                           ((pte_address[i*2]&0x80000000) >> 31), ((pte_address[i*2]&0x7fffff80) >> 7),
  378.                           ((pte_address[i*2]&0x00000040) >> 6), (pte_address[i*2] & 0x3f),
  379.                           ((pte_address[i*2+1]&0xfffff000) >> 12), ((pte_address[i*2+1]&0x00000100) >> 8),
  380.                           ((pte_address[i*2+1]&0x00000080) >> 7), ((pte_address[i*2+1]&0x00000078) >> 3),
  381.                           (pte_address[i*2+1]&0x00000003)));
  382.                         ra1 = (uint32)pe[1].address & 0xfffff000;
  383.                     }
  384.                 } else {
  385.                     if ((((uint32)pe[0].address + B_PAGE_SIZE) & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) {
  386.                         D(bug("Found page 1d PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n", 
  387.                           i << 2,
  388.                           ((pte_address[i*2]&0x80000000) >> 31), ((pte_address[i*2]&0x7fffff80) >> 7),
  389.                           ((pte_address[i*2]&0x00000040) >> 6), (pte_address[i*2] & 0x3f),
  390.                           ((pte_address[i*2+1]&0xfffff000) >> 12), ((pte_address[i*2+1]&0x00000100) >> 8),
  391.                           ((pte_address[i*2+1]&0x00000080) >> 7), ((pte_address[i*2+1]&0x00000078) >> 3),
  392.                           (pte_address[i*2+1]&0x00000003)));
  393.                         ra1 = ((uint32)pe[0].address + B_PAGE_SIZE) & 0xfffff000;
  394.                     }
  395.                 }
  396.             }
  397.  
  398.             // Map low memory for emulator
  399.             free_pte_0 = NULL;
  400.             free_pte_1 = NULL;
  401.             __sync();
  402.             __isync();
  403.             inval_tlb(0);
  404.             inval_tlb(B_PAGE_SIZE);
  405.             if (sysinfo.cpu_type != B_CPU_PPC_603 && sysinfo.cpu_type != B_CPU_PPC_603e)
  406.                 tlbsync();
  407.             res = map_page(0, ra0, &free_pte_0, 0x12);
  408.             if (res == B_NO_ERROR)
  409.                 res = map_page(B_PAGE_SIZE, ra1, &free_pte_1, 0x12);
  410.             inval_tlb(0);
  411.             inval_tlb(B_PAGE_SIZE);
  412.             if (sysinfo.cpu_type != B_CPU_PPC_603 && sysinfo.cpu_type != B_CPU_PPC_603e)
  413.                 tlbsync();
  414.             __sync();
  415.             __isync();
  416.  
  417.             // Restore interrupts
  418.             restore_interrupts(cpu_st);
  419.  
  420.             // Create port so we know that messing was successful
  421.             set_port_owner(create_port(1, PORT_NAME), B_SYSTEM_TEAM);
  422.             return B_NO_ERROR;
  423.  
  424.         case SHEEP_DOWN:
  425.             return B_NO_ERROR;
  426.  
  427.         default:
  428.             return B_BAD_VALUE;
  429.     }
  430. }
  431.  
  432.  
  433. /*
  434.  *  sheep_read - hook function for the read call
  435.  */
  436.  
  437. static status_t sheep_read(void *cookie, off_t pos, void *data, size_t *len)
  438. {
  439.     void *rom_adr;
  440.     area_id area;
  441.     system_info info;
  442.  
  443.     D(bug("read() pos %Lx, data %p, len %08x\n", pos, data, *len));
  444.  
  445.     get_system_info(&info);
  446.     if (info.platform_type == B_BEBOX_PLATFORM) {
  447.         *len = 0;
  448.         return B_ERROR;
  449.     }
  450.     if (*len != 0x400000 && pos != 0) {
  451.         *len = 0;
  452.         return B_BAD_VALUE;
  453.     }
  454.     area = map_physical_memory("mac_rom", (void *)0xff000000, 0x00400000, B_ANY_KERNEL_ADDRESS, B_READ_AREA, &rom_adr);
  455.     D(bug("Mapped ROM to %p, area id %d\n", rom_adr, area));
  456.     if (area < 0) {
  457.         *len = 0;
  458.         return area;
  459.     }
  460.     D(bug("Copying ROM\n"));
  461.     memcpy(data, rom_adr, *len);
  462.     D(bug("Deleting area\n"));
  463.     delete_area(area);
  464.     return B_NO_ERROR;
  465. }
  466.  
  467.  
  468. /*
  469.  *  sheep_write - hook function for the write call
  470.  */
  471.  
  472. static status_t sheep_write(void *cookie, off_t pos, const void *data, size_t *len)
  473. {
  474.     D(bug("write() pos %Lx, data %p, len %08x\n", pos, data, *len));
  475.     return B_READ_ONLY_DEVICE;
  476. }
  477.